/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

// import { Alert, Button } from 'antd';
import { pickedFaceData, pickedLineData, pickedVertexData } from '@amcax/base';
import {
  NumberInputFormat,
  PickInputRJSFFormat,
} from '@app-cad/common/components/command-form/constants';
import { PickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import { getIdOfPickedObj } from '@app-cad/common/utils/render';
import { CurvedBaseCommand, CurvedCmdDialogParams } from '@app-cad/types';
import { RJSFSchema } from '@rjsf/utils';
import { useAsyncEffect } from 'ahooks';
import i18n from 'i18next';
import { useEffect, useMemo, useState } from 'react';
import { Vector3Tuple } from 'three-legacy';

type pickedDirection = pickedLineData | pickedFaceData;
type pickedReference = pickedLineData | pickedFaceData | pickedVertexData;

type FormData = {
  mode: 'standard' | 'rotate' | 'euler';
  origin?: pickedVertexData;
  xdir?: pickedDirection;
  ydir?: pickedDirection;
  zdir?: pickedDirection;

  axis?: pickedReference;
  angle?: number;

  anglex?: number;
  angley?: number;
  anglez?: number;
};

type Params = {
  mode: 'standard' | 'rotate' | 'euler';
  origin?: string | Vector3Tuple;
  xdir?: string | Vector3Tuple;
  xreverse?: boolean;
  ydir?: string | Vector3Tuple;
  yreverse?: boolean;
  zdir?: string | Vector3Tuple;
  zreverse?: boolean;

  axis?: string | Vector3Tuple;
  angle?: number;

  anglex?: number;
  angley?: number;
  anglez?: number;
};

function CmdCsys({ title, onClose, props }: CurvedCmdDialogParams) {
  const initData: FormData = {
    mode: 'standard',
    angle: 0,
    anglex: 0,
    angley: 0,
    anglez: 0,
  };
  const [formData, setFormData] = useState<FormData>(initData);

  const schema: RJSFSchema = useMemo(() => {
    const axes =
      formData.mode === 'euler'
        ? {}
        : {
            xdir: {
              type: 'string',
              format: PickInputRJSFFormat.PickDirection,
            },
            ydir: {
              type: 'string',
              format: PickInputRJSFFormat.PickDirection,
            },
            zdir: {
              type: 'string',
              format: PickInputRJSFFormat.PickDirection,
            },
          };

    return {
      type: 'object',
      properties: {
        mode: {
          type: 'string',
          default: 'standard',
          title: '坐标系类型',
          oneOf: [
            {
              title: '标准',
              const: 'standard',
            },
            {
              title: '轴旋转',
              const: 'rotate',
            },
            {
              title: '欧拉角',
              const: 'euler',
            },
          ],
        },
        origin: {
          type: 'string',
          format: PickInputRJSFFormat.PickVertex,
        },
        ...axes,
        ...(formData.mode === 'rotate'
          ? {
              axis: {
                type: 'string',
                format: PickInputRJSFFormat.PickFrameReference,
              },
              angle: {
                type: 'number',
                title: '旋转角度',
                format: NumberInputFormat.Angle,
              },
            }
          : {}),
        ...(formData.mode === 'euler'
          ? {
              anglex: {
                type: 'number',
                title: '角度1',
                format: NumberInputFormat.Angle,
              },
              angley: {
                type: 'number',
                title: '角度2',
                format: NumberInputFormat.Angle,
              },
              anglez: {
                type: 'number',
                title: '角度3',
                format: NumberInputFormat.Angle,
              },
            }
          : {}),
      },
    } as RJSFSchema;
  }, [formData]);

  const { picker } = useTools();

  useEffect(() => {
    if (isFormDataValid()) {
      execute(true);
    }
  }, [formData]);

  useAsyncEffect(async () => {
    if (props == null) {
      setFormData(initData);
      return;
    }

    const {
      mode,
      origin,
      xdir,
      xreverse,
      ydir,
      yreverse,
      zdir,
      zreverse,
      axis,
      angle,
      anglex,
      angley,
      anglez,
    } = props.params as Params;

    await initEditDependency(
      [origin, xdir, ydir, zdir, axis].filter((v) => typeof v === 'string'),
    );

    const parseIfString = (val: string | Vector3Tuple, reverse?: boolean) => {
      if (typeof val === 'string') {
        const res = picker.generatePickObjByPickID(val, {
          showArrow: reverse != null,
        });

        if ((res as pickedLineData)?.edgeId != null && reverse) {
          (res as pickedLineData).assisObj.reverse();
        }

        return res;
      }

      return null;
    };

    setFormData({
      mode,
      origin: parseIfString(origin) as pickedVertexData,
      xdir: parseIfString(xdir, xreverse) as pickedDirection,
      ydir: parseIfString(ydir, yreverse) as pickedDirection,
      zdir: parseIfString(zdir, zreverse) as pickedDirection,
      axis: parseIfString(axis) as pickedReference,
      angle,
      anglex,
      angley,
      anglez,
    });
  }, []);

  const isFormDataValid = () => {
    const {
      mode,
      origin,
      xdir,
      ydir,
      zdir,
      axis,
      angle,
      anglex,
      angley,
      anglez,
    } = formData;

    const hasOrigin = origin != null;

    const dirNum = [xdir, ydir, zdir].filter((v) => v != null).length;

    const isStandardValid = hasOrigin && (dirNum === 0 || dirNum === 2);

    const isRotateValid =
      hasOrigin && axis != null && angle !== null && dirNum === 1;

    const isEulerValid =
      hasOrigin && anglex != null && angley != null && anglez != null;

    return (
      (mode === 'standard' && isStandardValid) ||
      (mode === 'rotate' && isRotateValid) ||
      (mode === 'euler' && isEulerValid)
    );
  };

  const execute = async (preview: boolean) => {
    const {
      mode,
      origin,
      xdir,
      ydir,
      zdir,
      axis,
      angle,
      anglex,
      angley,
      anglez,
    } = formData;

    const getReverse = (v: pickedDirection) => {
      if (v == null) {
        return null;
      }
      return (v as pickedLineData)?.edgeId != null
        ? (v as pickedLineData).assisObj.isReversed
        : false;
    };
    const nonEulerParams =
      mode === 'euler'
        ? {}
        : {
            xdir: getIdOfPickedObj(xdir),
            xreverse: getReverse(xdir),
            ydir: getIdOfPickedObj(ydir),
            yreverse: getReverse(ydir),
            zdir: getIdOfPickedObj(zdir),
            zreverse: getReverse(zdir),
          };

    const rotateParams =
      mode === 'rotate'
        ? {
            axis: getIdOfPickedObj(axis),
            angle,
          }
        : {};

    const eulerParams =
      mode === 'euler'
        ? {
            anglex,
            angley,
            anglez,
          }
        : {};

    await confirmCommand(
      {
        a: {
          mode,
          origin: origin.vertexId,
          ...nonEulerParams,
          ...rotateParams,
          ...eulerParams,
        } as Params,
      },
      preview,
    );
  };

  const checkAndFinishDraw = async () => {
    if (!isFormDataValid()) {
      return;
    }

    await execute(false);

    onClose();
  };

  const { initEditDependency, initingEdit, confirmCommand, isLoading } =
    useCommand('cmd-csys', {
      onClose,
      finishDraw: checkAndFinishDraw,
      commandName: 'CreateFrame',
      editDxid: (props as any)?.dxid,
    });

  const isAxisOptional = formData.mode === 'standard';
  const axisPlaceholderHint = isAxisOptional ? '可选' : '选填一个坐标轴';

  return (
    <PickableCommandForm
      disabled={initingEdit}
      submitLoading={isLoading}
      onClose={onClose}
      title={title}
      schema={schema}
      formData={formData}
      extraUiSchema={{
        origin: {
          'ui:placeholder': '原点',
          'ui:autofocus': true,
        },
        xdir: {
          'ui:placeholder': `x轴(${axisPlaceholderHint})`,
          'ui:options': {
            showArrow: true,
            curveReversable: true,
          },
          'ui:disabled': isAxisOptional
            ? formData.ydir != null && formData.zdir != null
            : formData.ydir != null || formData.zdir != null,
        },
        ydir: {
          'ui:placeholder': `y轴(${axisPlaceholderHint})`,
          'ui:options': {
            showArrow: true,
            curveReversable: true,
          },
          'ui:disabled': isAxisOptional
            ? formData.xdir != null && formData.zdir != null
            : formData.xdir != null || formData.zdir != null,
        },
        zdir: {
          'ui:placeholder': `z轴(${axisPlaceholderHint})`,
          'ui:options': {
            showArrow: true,
            curveReversable: true,
          },
          'ui:disabled': isAxisOptional
            ? formData.ydir != null && formData.xdir != null
            : formData.ydir != null || formData.xdir != null,
        },
        axis: {
          'ui:placeholder': '参考',
          'ui:options': {
            allowInfiniteLine: true,
            allowInfinitePlane: true,
          },
        },
      }}
      submitText='完成'
      onChange={(data) => {
        setFormData(data);
      }}
      onSubmit={checkAndFinishDraw}
      isFormDataValid={isFormDataValid()}
    />
  );
}

export const cmdCsys: CurvedBaseCommand = {
  id: 'CmdCsys',
  label: 'command.csys',
  icon: 'commands/curved/axis-system',
  help: {
    remark: 'tips.redo',
  },
  create: (label, onClose, props) => (
    <CmdCsys
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
